package com.ymx.darling.spring;

import com.ymx.darling.log.Log;
import com.ymx.darling.log.LogFactory;
import com.ymx.darling.session.Session;
import com.ymx.darling.session.SessionFactory;
import com.ymx.darling.spring.transaction.SpringTransactionManager;
import com.ymx.darling.transaction.TransactionManager;
import org.springframework.core.Ordered;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

/**
 * @author 爱Java的小于
 */
public class SessionUtils {
    // 日志对象，用于记录调试信息
    private static final Log log = LogFactory.getLog(SessionUtils.class.getName());

    // 私有构造函数，防止实例化
    private SessionUtils() {
    }

    /**
     * 获取Session对象
     * 如果当前事务中没有Session，则创建一个新的Session
     *
     * @param sessionFactory Session工厂，用于创建Session对象
     * @return 当前事务中的Session对象
     */
    public static Session getSession(SessionFactory sessionFactory) {
        Assert.notNull(sessionFactory, "未指定SessionFactory");
        SessionHolder holder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
        Session session = sessionHolder(holder);
        if (session == null) {
            if (log.isDebugEnabled()) {
                log.debug("正在创建新Session");
            }
            session = sessionFactory.openSession();
            registerSessionHolder(sessionFactory, session);
        }
        return session;
    }

    /**
     * 注册SessionHolder到事务同步管理器中
     *
     * @param sessionFactory Session工厂
     * @param session 当前Session对象
     */
    private static void registerSessionHolder(SessionFactory sessionFactory, Session session) {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionManager transactionFactory = sessionFactory.getConfiguration().getTransactionFactory();
            if (transactionFactory instanceof SpringTransactionManager) {
                if (log.isDebugEnabled()) {
                    log.debug("正在为SqlSession [" + session + "] 注册事务同步处理");
                }
                SessionHolder holder = new SessionHolder(session);
                TransactionSynchronizationManager.bindResource(sessionFactory, holder);
                TransactionSynchronizationManager.registerSynchronization(new SessionSynchronization(holder, sessionFactory));
                holder.setSynchronizedWithTransaction(true);
                holder.requested();
            } else {
                if (TransactionSynchronizationManager.getResource(transactionFactory.getDataSource()) != null) {
                    throw new TransientDataAccessResourceException(
                            "检测到非法配置: 当前SessionFactory未使用SpringManagedTransactionFactory,无法启用Spring事务同步");                }
                if (log.isDebugEnabled()) {
                    log.debug("检测到非事务性数据源,会话 [" + session + "] 跳过事务同步注册");                }
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("由于同步功能处于禁用状态,会话 [" + session + "] 跳过同步注册");
            }
        }
    }

    /**
     * 从SessionHolder中获取Session对象
     *
     * @param holder SessionHolder对象
     * @return 当前事务中的Session对象
     */
    private static Session sessionHolder(SessionHolder holder) {
        Session session = null;
        if (holder != null && holder.isSynchronizedWithTransaction()) {
            holder.requested();
            if (log.isDebugEnabled()) {
                log.debug("从事务上下文中获取SqlSession [" + holder.getSession() + "]");            }
            session = holder.getSession();
        }
        return session;
    }

    /**
     * 关闭Session对象
     * 如果Session是事务性的，则释放它；否则直接关闭
     *
     * @param session 当前Session对象
     * @param sessionFactory Session工厂
     */
    public static void closeSession(Session session, SessionFactory sessionFactory) {
        Assert.notNull(session, "未指定Session");
        Assert.notNull(sessionFactory, "未指定SessionFactory");
        SessionHolder holder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
        if (holder != null && holder.getSession() == session) {
            if (log.isDebugEnabled()) {
                log.debug("正在释放事务型会话 [" + session + "]");
            }
            holder.released();
        } else {
            if (log.isDebugEnabled()) {
                log.debug("正在关闭非事务型会话 [" + session + "]");
            }
            session.close();
        }
    }

    /**
     * 检查Session是否是事务性的
     *
     * @param session 当前Session对象
     * @param sessionFactory Session工厂
     * @return 如果Session是事务性的，则返回true；否则返回false
     */
    public static boolean isSessionTransactional(Session session, SessionFactory sessionFactory) {
        Assert.notNull(session, "未指定Session");
        Assert.notNull(sessionFactory, "未指定SessionFactory");
        SessionHolder holder = (SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory);
        return holder != null && holder.getSession() == session;
    }

    /**
     * 设置spring回调
     */
    private static final class SessionSynchronization implements TransactionSynchronization, Ordered {
        private final SessionHolder holder;
        private final SessionFactory sessionFactory;
        private boolean holderActive = true;

        public SessionSynchronization(SessionHolder holder, SessionFactory sessionFactory) {
            Assert.notNull(holder, "参数'holder'不能为null");
            Assert.notNull(sessionFactory, "参数'sessionFactory'不能为null");
            this.holder = holder;
            this.sessionFactory = sessionFactory;
        }

        public int getOrder() {
            return 999;
        }

        public void suspend() {
            if (this.holderActive) {
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在挂起会话 [" + this.holder.getSession() + "]");                }
                TransactionSynchronizationManager.unbindResource(this.sessionFactory);
            }
        }

        public void resume() {
            if (this.holderActive) {
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在恢复会话 [" + this.holder.getSession() + "]");                }
                TransactionSynchronizationManager.bindResource(this.sessionFactory, this.holder);
            }
        }

        public void beforeCommit(boolean readOnly) {
            if (TransactionSynchronizationManager.isActualTransactionActive()) {
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在提交会话 [" + this.holder.getSession() + "]");                }
                this.holder.getSession().commit();
            }
        }

        public void beforeCompletion() {
            if (!this.holder.isOpen()) {
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在注销会话 [" + this.holder.getSession() + "]");                }
                TransactionSynchronizationManager.unbindResource(this.sessionFactory);
                this.holderActive = false;
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在关闭会话 [" + this.holder.getSession() + "]");                }
                this.holder.getSession().close();
            }
        }

        public void afterCompletion(int status) {
            if (this.holderActive) {
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制解除会话注册 [" + this.holder.getSession() + "]");                }
                TransactionSynchronizationManager.unbindResourceIfPossible(this.sessionFactory);
                this.holderActive = false;
                if (log.isDebugEnabled()) {
                    log.debug("事务同步机制正在关闭会话 [" + this.holder.getSession() + "]");                }
                this.holder.getSession().close();
            }
            this.holder.reset();
        }
    }
}

